"""
REST API服务器
为红外温度分析系统提供HTTP API接口
支持视频流控制和区域温度分析功能
"""

from flask import Flask, request, jsonify, send_from_directory, redirect, url_for
from flask_cors import CORS
import logging
import json
import os
import threading
import time
from typing import Dict, Any, List
import traceback
import cv2
import numpy as np
import io
from werkzeug.utils import secure_filename
from PIL import Image
import base64

from .thermal_analysis_engine import ThermalService
from ..core.data_storage import DataStorage
from ..core.temperature_mapper import TemperatureMapper
from ..core.hybrid_temperature_processor import get_hybrid_processor


class ThermalAPIServer:
    """热成像温度分析API服务器"""
    
    def __init__(self, host: str = '0.0.0.0', port: int = 5000, debug: bool = False):
        """
        初始化API服务器
        
        Args:
            host: 服务器主机地址
            port: 服务器端口
            debug: 调试模式
        """
        self.host = host
        self.port = port
        self.debug = debug
        
        # 初始化Flask应用（禁用默认静态文件处理）
        self.app = Flask(__name__, static_folder=None)
        self.app.config['JSON_AS_ASCII'] = False  # 支持中文JSON响应
        CORS(self.app)  # 启用CORS支持
        
        # 初始化核心服务
        self.data_storage = DataStorage()
        self.thermal_service = ThermalService(self.data_storage)
        self.hybrid_processor = get_hybrid_processor()
        
        # 配置日志
        logging.basicConfig(
            level=logging.INFO,
            format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
        )
        self.logger = logging.getLogger(__name__)
        
        # 注册路由
        self._register_routes()
        
        # 服务器状态
        self.server_start_time = None
        self.request_count = 0
        self.request_count_lock = threading.Lock()
        
        # 支持的图片格式（包含R-JPEG）
        self.ALLOWED_EXTENSIONS = {'jpg', 'jpeg', 'png', 'bmp', 'rjpeg', 'r.jpg'}
        
    def _is_allowed_file(self, filename):
        """检查文件扩展名是否被允许"""
        return '.' in filename and \
               filename.rsplit('.', 1)[1].lower() in self.ALLOWED_EXTENSIONS
               
    def _register_routes(self):
        """注册API路由"""
        
        @self.app.route('/api/health', methods=['GET'])
        def health_check():
            """健康检查接口"""
            with self.request_count_lock:
                self.request_count += 1
                
            uptime = time.time() - self.server_start_time if self.server_start_time else 0
            
            return jsonify({
                'status': 'healthy',
                'message': '温度分析API服务正常运行',
                'uptime_seconds': uptime,
                'request_count': self.request_count,
                'stream_status': self.thermal_service.get_stream_status()
            })
            
        @self.app.route('/api/shutdown', methods=['POST'])
        def shutdown_server():
            """优雅关闭API服务器"""
            try:
                with self.request_count_lock:
                    self.request_count += 1
                
                self.logger.info("收到服务器关闭请求")
                
                # 停止视频流（如果正在运行）
                if self.thermal_service.is_streaming:
                    self.logger.info("停止正在运行的视频流...")
                    self.thermal_service.stop_stream_analysis()
                
                # 保存当前标定点
                try:
                    file_path = self.thermal_service.save_calibration_points()
                    self.logger.info(f"标定点已保存到: {file_path}")
                except Exception as e:
                    self.logger.warning(f"保存标定点失败: {e}")
                
                # 清理资源
                self.thermal_service.cleanup()
                
                response_data = {
                    'success': True,
                    'message': 'API服务器正在关闭...',
                    'uptime_seconds': time.time() - self.server_start_time if self.server_start_time else 0,
                    'total_requests': self.request_count
                }
                
                # 延迟关闭服务器，让响应能够正常返回
                def delayed_shutdown():
                    time.sleep(1)
                    self.logger.info("API服务器关闭完成")
                    os._exit(0)
                
                import threading
                threading.Thread(target=delayed_shutdown, daemon=True).start()
                
                return jsonify(response_data), 200
                
            except Exception as e:
                self.logger.error(f"关闭服务器时发生错误: {e}")
                return jsonify({
                    'success': False,
                    'message': f'关闭失败: {str(e)}'
                }), 500
            
        @self.app.route('/api/start_stream', methods=['POST'])
        def start_stream():
            """开启温度分析 - 启动视频流"""
            try:
                with self.request_count_lock:
                    self.request_count += 1
                    
                # 解析请求参数
                data = request.get_json()
                if not data:
                    return jsonify({
                        'success': False,
                        'message': '请求体不能为空，需要提供stream_url参数'
                    }), 400
                    
                stream_url = data.get('stream_url')
                if not stream_url:
                    return jsonify({
                        'success': False,
                        'message': '缺少必需参数: stream_url'
                    }), 400
                    
                # 可选参数
                fps_limit = data.get('fps_limit', 10)
                frame_skip = data.get('frame_skip', 1)
                
                self.logger.info(f"收到启动视频流请求: {stream_url}")
                
                # 启动流分析
                result = self.thermal_service.start_stream_analysis(
                    stream_url=stream_url,
                    fps_limit=fps_limit,
                    frame_skip=frame_skip
                )
                
                if result['success']:
                    self.logger.info(f"视频流启动成功: {stream_url}")
                    return jsonify(result), 200
                else:
                    self.logger.warning(f"视频流启动失败: {result['message']}")
                    return jsonify(result), 400
                    
            except Exception as e:
                self.logger.error(f"启动视频流时发生错误: {e}")
                self.logger.error(traceback.format_exc())
                return jsonify({
                    'success': False,
                    'message': f'服务器内部错误: {str(e)}'
                }), 500
                
        @self.app.route('/api/stop_stream', methods=['POST'])
        def stop_stream():
            """关闭温度分析 - 停止视频流"""
            try:
                with self.request_count_lock:
                    self.request_count += 1
                    
                self.logger.info("收到停止视频流请求")
                
                # 停止流分析
                result = self.thermal_service.stop_stream_analysis()
                
                if result['success']:
                    self.logger.info("视频流停止成功")
                    return jsonify(result), 200
                else:
                    self.logger.warning(f"视频流停止失败: {result['message']}")
                    return jsonify(result), 400
                    
            except Exception as e:
                self.logger.error(f"停止视频流时发生错误: {e}")
                self.logger.error(traceback.format_exc())
                return jsonify({
                    'success': False,
                    'message': f'服务器内部错误: {str(e)}'
                }), 500
                
        @self.app.route('/api/analyze_regions', methods=['POST'])
        def analyze_regions():
            """区域温度分析接口"""
            try:
                with self.request_count_lock:
                    self.request_count += 1
                    
                # 解析请求参数
                data = request.get_json()
                if not data:
                    return jsonify({
                        'success': False,
                        'message': '请求体不能为空，需要提供regions参数'
                    }), 400
                    
                regions = data.get('regions')
                if not regions:
                    return jsonify({
                        'success': False,
                        'message': '缺少必需参数: regions'
                    }), 400
                    
                if not isinstance(regions, list):
                    return jsonify({
                        'success': False,
                        'message': 'regions参数必须是数组格式'
                    }), 400
                    
                # 验证区域数据格式
                for i, region in enumerate(regions):
                    required_keys = ['x1', 'y1', 'x2', 'y2']
                    missing_keys = [key for key in required_keys if key not in region]
                    if missing_keys:
                        return jsonify({
                            'success': False,
                            'message': f'区域{i+1}缺少必需的坐标参数: {missing_keys}'
                        }), 400
                        
                    # 检查坐标类型
                    try:
                        for key in required_keys:
                            int(region[key])
                    except (ValueError, TypeError):
                        return jsonify({
                            'success': False,
                            'message': f'区域{i+1}的坐标参数必须为整数: {region}'
                        }), 400
                        
                # 可选参数
                save_result = data.get('save_result', True)
                image_source = data.get('image_source', 'api_request')
                
                self.logger.info(f"收到区域温度分析请求，共{len(regions)}个区域")
                
                # 执行区域分析
                result = self.thermal_service.analyze_regions(
                    regions=regions,
                    save_result=save_result,
                    image_source=image_source
                )
                
                if result['success']:
                    self.logger.info(f"区域温度分析完成，分析了{len(result['regions'])}个区域")
                    return jsonify(result), 200
                else:
                    self.logger.warning(f"区域温度分析失败: {result['message']}")
                    return jsonify(result), 400
                    
            except Exception as e:
                self.logger.error(f"区域温度分析时发生错误: {e}")
                self.logger.error(traceback.format_exc())
                return jsonify({
                    'success': False,
                    'message': f'服务器内部错误: {str(e)}'
                }), 500
                
        @self.app.route('/api/stream_status', methods=['GET'])
        def get_stream_status():
            """获取视频流状态"""
            try:
                with self.request_count_lock:
                    self.request_count += 1
                    
                status = self.thermal_service.get_stream_status()
                return jsonify({
                    'success': True,
                    'status': status
                }), 200
                
            except Exception as e:
                self.logger.error(f"获取流状态时发生错误: {e}")
                return jsonify({
                    'success': False,
                    'message': f'获取状态失败: {str(e)}'
                }), 500
                
        @self.app.route('/api/calibration', methods=['POST'])
        def manage_calibration():
            """管理温度标定点"""
            try:
                with self.request_count_lock:
                    self.request_count += 1
                    
                # 处理不同的请求格式
                if request.is_json:
                    data = request.get_json()
                    action = data.get('action', 'add')
                elif request.form:
                    data = request.form.to_dict()
                    action = data.get('action', 'add')
                else:
                    return jsonify({
                        'success': False,
                        'message': '请求格式错误，需要JSON或FormData格式'
                    }), 400
                
                self.logger.info(f"标定接口收到请求，action: {action}")
                
                if action == 'add':
                    # 添加标定点
                    required_keys = ['x', 'y', 'temperature']
                    missing_keys = [key for key in required_keys if key not in data]
                    if missing_keys:
                        return jsonify({
                            'success': False,
                            'message': f'缺少必需参数: {missing_keys}'
                        }), 400
                        
                    # 调用thermal_service的add_calibration_point方法
                    # 该方法会自动获取指定坐标的HSV颜色值
                    success = self.thermal_service.add_calibration_point(
                        x=data['x'],
                        y=data['y'], 
                        temperature=data['temperature']
                    )
                    
                    if not success:
                        return jsonify({
                            'success': False,
                            'message': '标定点添加失败，请确保已加载图片且坐标有效'
                        }), 400
                    
                    # 获取更新后的标定点信息
                    calibration_points = self.thermal_service.get_calibration_points()
                    
                    return jsonify({
                        'success': True,
                        'message': '标定点添加成功',
                        'calibration_points_count': len(calibration_points),
                        'calibration_points': [
                            {
                                'position': point.position,
                                'temperature': point.temperature,
                                'hsv_color': point.hsv_color.tolist() if hasattr(point.hsv_color, 'tolist') else point.hsv_color,
                                'index': point.index
                            } for point in calibration_points
                        ]
                    }), 200
                    
                elif action == 'clear':
                    # 清空标定点
                    self.thermal_service.clear_calibration_points()
                    
                    return jsonify({
                        'success': True,
                        'message': '标定点已清空并保存到文件'
                    }), 200
                    
                elif action == 'remove':
                    # 删除单个标定点
                    index = data.get('index')
                    if index is None:
                        return jsonify({
                            'success': False,
                            'message': '缺少必需参数: index'
                        }), 400
                    
                    try:
                        success = self.thermal_service.remove_calibration_point(index)
                        
                        if success:
                            calibration_points = self.thermal_service.get_calibration_points()
                            return jsonify({
                                'success': True,
                                'message': f'标定点 {index} 已删除并保存到文件',
                                'calibration_points_count': len(calibration_points),
                                'calibration_points': [
                                    {
                                        'position': point.position,
                                        'temperature': point.temperature,
                                        'hsv_color': point.hsv_color.tolist() if hasattr(point.hsv_color, 'tolist') else point.hsv_color,
                                        'index': point.index
                                    } for point in calibration_points
                                ]
                            }), 200
                        else:
                            return jsonify({
                                'success': False,
                                'message': f'删除失败: 无效的索引 {index}'
                            }), 400
                    except Exception as e:
                        return jsonify({
                            'success': False,
                            'message': f'删除标定点失败: {str(e)}'
                        }), 500
                    
                elif action == 'save':
                    # 手动保存标定点到文件
                    try:
                        file_path = self.thermal_service.save_calibration_points()
                        calibration_points = self.thermal_service.get_calibration_points()
                        
                        return jsonify({
                            'success': True,
                            'message': '标定点已保存到文件',
                            'file_path': file_path,
                            'calibration_points_count': len(calibration_points)
                        }), 200
                    except Exception as e:
                        return jsonify({
                            'success': False,
                            'message': f'保存标定点失败: {str(e)}'
                        }), 500
                        
                elif action == 'load':
                    # 从文件加载标定点
                    file_path = data.get('file_path')  # 可选，如果不提供则加载最新文件
                    
                    try:
                        success = self.thermal_service.load_calibration_points(file_path)
                        
                        if success:
                            calibration_points = self.thermal_service.get_calibration_points()
                            return jsonify({
                                'success': True,
                                'message': f'成功加载 {len(calibration_points)} 个标定点',
                                'calibration_points_count': len(calibration_points),
                                'calibration_points': [
                                    {
                                        'position': point.position,
                                        'temperature': point.temperature,
                                        'hsv_color': point.hsv_color.tolist() if hasattr(point.hsv_color, 'tolist') else point.hsv_color,
                                        'index': point.index
                                    } for point in calibration_points
                                ]
                            }), 200
                        else:
                            return jsonify({
                                'success': False,
                                'message': '加载标定点失败，未找到有效的标定点文件'
                            }), 404
                    except Exception as e:
                        return jsonify({
                            'success': False,
                            'message': f'加载标定点失败: {str(e)}'
                        }), 500
                        
                elif action == 'files':
                    # 获取标定点文件列表
                    try:
                        import os
                        files = self.thermal_service.get_calibration_files()
                        file_info = []
                        
                        for file_path in files:
                            try:
                                stat = os.stat(file_path)
                                file_info.append({
                                    'path': file_path,
                                    'name': os.path.basename(file_path),
                                    'size': stat.st_size,
                                    'modified_time': stat.st_mtime,
                                    'modified_date': time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(stat.st_mtime))
                                })
                            except Exception as e:
                                self.logger.warning(f"获取文件信息失败: {file_path}, {e}")
                                continue
                        
                        return jsonify({
                            'success': True,
                            'message': f'找到 {len(file_info)} 个标定点文件',
                            'files': file_info
                        }), 200
                    except Exception as e:
                        return jsonify({
                            'success': False,
                            'message': f'获取文件列表失败: {str(e)}'
                        }), 500
                        
                elif action == 'auto_calibrate':
                    # 使用R-JPEG文件自动标定HSV温度映射
                    if 'rjpeg_file' not in request.files:
                        return jsonify({
                            'success': False,
                            'message': '缺少必需参数: rjpeg_file'
                        }), 400
                    
                    rjpeg_file = request.files['rjpeg_file']
                    positions_str = data.get('positions')  # [{"x": 100, "y": 200}, ...]
                    
                    if not positions_str:
                        return jsonify({
                            'success': False,
                            'message': '缺少必需参数: positions'
                        }), 400
                    
                    try:
                        import json
                        import tempfile
                        import os
                        
                        positions = json.loads(positions_str) if isinstance(positions_str, str) else positions_str
                        
                        # 保存临时R-JPEG文件
                        tmp_path = None
                        with tempfile.NamedTemporaryFile(delete=False, suffix='.rjpeg') as tmp_file:
                            rjpeg_file.save(tmp_file.name)
                            tmp_path = tmp_file.name
                        
                        try:
                            # 使用TSDK处理R-JPEG获取精确温度
                            process_result = self.hybrid_processor.process_image(tmp_path, force_mode='tsdk')
                            if not process_result.get('success'):
                                raise Exception(process_result.get('message', 'TSDK处理失败'))
                            
                            # 同时加载为普通图像获取HSV值
                            cv_image = cv2.imread(tmp_path)
                            if cv_image is None:
                                raise Exception("无法加载图像文件")
                            
                            hsv_image = cv2.cvtColor(cv_image, cv2.COLOR_BGR2HSV)
                            
                            # 清空现有标定点
                            self.thermal_service.clear_calibration_points(auto_save=False)
                            
                            # 为每个位置创建标定点
                            calibration_results = []
                            for pos in positions:
                                x, y = int(pos['x']), int(pos['y'])
                                
                                # 获取TSDK精确温度
                                tsdk_temp_data = self.hybrid_processor.get_temperature_at_point(x, y)
                                tsdk_temp = tsdk_temp_data['temperature']
                                
                                # 获取HSV值
                                hsv_color = hsv_image[y, x].tolist()
                                
                                # 添加标定点
                                self.thermal_service.temp_mapper.add_calibration_point(
                                    hsv_color, tsdk_temp, (x, y)
                                )
                                
                                calibration_results.append({
                                    'position': {'x': x, 'y': y},
                                    'hsv_color': hsv_color,
                                    'tsdk_temperature': round(tsdk_temp, 2),
                                    'method': 'tsdk_auto_calibration'
                                })
                                
                                self.logger.info(f"自动标定: ({x},{y}) HSV{hsv_color} -> {tsdk_temp:.1f}°C")
                            
                            # 保存标定点到文件
                            self.thermal_service.save_calibration_points()
                            
                            return jsonify({
                                'success': True,
                                'message': f'成功创建 {len(positions)} 个自动标定点',
                                'calibration_results': calibration_results,
                                'total_points': len(calibration_results)
                            }), 200
                            
                        finally:
                            # 清理临时文件 - 暂时禁用避免os作用域错误
                            # if tmp_path and os.path.exists(tmp_path):
                            #     os.unlink(tmp_path)
                            pass
                                
                    except Exception as e:
                        return jsonify({
                            'success': False,
                            'message': f'自动标定失败: {str(e)}'
                        }), 500
                
                elif action == 'grid_auto_calibrate':
                    # 网格自动标定
                    if 'rjpeg_file' not in request.files:
                        return jsonify({
                            'success': False,
                            'message': '缺少必需参数: rjpeg_file'
                        }), 400
                    
                    rjpeg_file = request.files['rjpeg_file']
                    grid_size = request.form.get('grid_size', '8x6')  # 默认8x6网格
                    full_coverage = request.form.get('full_coverage', 'false').lower() == 'true'  # 是否全图覆盖
                    
                    try:
                        # 解析网格尺寸
                        grid_width, grid_height = map(int, grid_size.split('x'))
                        if grid_width < 2 or grid_height < 2 or grid_width > 50 or grid_height > 50:
                            raise ValueError("网格尺寸无效，应在2x2到50x50之间")
                    except ValueError as e:
                        return jsonify({
                            'success': False,
                            'message': f'网格尺寸格式错误: {str(e)}'
                        }), 400
                    
                    # 保存临时文件
                    import tempfile
                    tmp_path = None
                    with tempfile.NamedTemporaryFile(delete=False, suffix='.rjpeg') as tmp_file:
                        rjpeg_file.save(tmp_file.name)
                        tmp_path = tmp_file.name
                    
                    try:
                        # 使用TSDK处理R-JPEG
                        process_result = self.hybrid_processor.process_image(tmp_path, force_mode='tsdk')
                        visible_image = process_result['visible_image']
                        vis_height, vis_width = visible_image.shape[:2]
                        
                        # 生成网格坐标
                        grid_points = self._generate_grid_points(vis_width, vis_height, grid_width, grid_height, full_coverage)
                        
                        # 批量获取温度和HSV数据
                        hsv_image = cv2.cvtColor(visible_image, cv2.COLOR_BGR2HSV)
                        calibration_results = []
                        
                        for point in grid_points:
                            x, y = point['x'], point['y']
                            
                            try:
                                # 获取TSDK温度
                                temp_data = self.hybrid_processor.get_temperature_at_point(x, y)
                                tsdk_temp = temp_data['temperature']
                                
                                # 获取HSV颜色
                                hsv_color = hsv_image[y, x].tolist()
                                
                                # 添加标定点
                                self.thermal_service.temp_mapper.add_calibration_point(hsv_color, tsdk_temp, (x, y))
                                
                                calibration_results.append({
                                    'position': {'x': x, 'y': y},
                                    'temperature': round(tsdk_temp, 2),
                                    'hsv_color': hsv_color,
                                    'mapped_coordinates': temp_data.get('mapped_coordinates')
                                })
                                
                            except Exception as e:
                                self.logger.warning(f"网格点({x},{y})处理失败: {e}")
                                continue
                        
                        # 保存标定数据
                        save_path = self.thermal_service.save_calibration_points()
                        
                        return jsonify({
                            'success': True,
                            'message': f'网格自动标定完成',
                            'grid_size': grid_size,
                            'full_coverage': full_coverage,
                            'total_points': len(calibration_results),
                            'calibration_results': calibration_results,
                            'save_path': save_path,
                            'calibration_points_count': len(self.thermal_service.temp_mapper.get_calibration_info()),
                            'image_resolution': {'width': vis_width, 'height': vis_height}
                        }), 200
                        
                    except Exception as e:
                        return jsonify({
                            'success': False,
                            'message': f'网格自动标定失败: {str(e)}'
                        }), 500
                        
                    finally:
                        # 清理临时文件 - 暂时禁用避免os作用域错误
                        # if tmp_path and os.path.exists(tmp_path):
                        #     os.unlink(tmp_path)
                        pass
                
                elif action == 'get':
                    # 获取标定点信息
                    calibration_points = self.thermal_service.get_calibration_points()
                    
                    return jsonify({
                        'success': True,
                        'calibration_points': [
                            {
                                'position': point.position,
                                'temperature': point.temperature,
                                'hsv_color': point.hsv_color.tolist() if hasattr(point.hsv_color, 'tolist') else point.hsv_color,
                                'index': point.index
                            } for point in calibration_points
                        ],
                        'count': len(calibration_points)
                    }), 200
                    
                else:
                    return jsonify({
                        'success': False,
                        'message': f'不支持的操作: {action}'
                    }), 400
                    
            except Exception as e:
                self.logger.error(f"管理标定点时发生错误: {e}")
                return jsonify({
                    'success': False,
                    'message': f'服务器内部错误: {str(e)}'
                }), 500
                
        @self.app.route('/api/calibration/files', methods=['GET'])
        def get_calibration_files():
            """获取标定点文件列表"""
            try:
                with self.request_count_lock:
                    self.request_count += 1
                    
                files = self.thermal_service.get_calibration_files()
                file_info = []
                
                for file_path in files:
                    try:
                        import os
                        stat = os.stat(file_path)
                        file_info.append({
                            'path': file_path,
                            'name': os.path.basename(file_path),
                            'size': stat.st_size,
                            'modified_time': stat.st_mtime,
                            'modified_date': time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(stat.st_mtime))
                        })
                    except Exception as e:
                        self.logger.warning(f"获取文件信息失败: {file_path}, {e}")
                        continue
                
                return jsonify({
                    'success': True,
                    'message': f'找到 {len(file_info)} 个标定点文件',
                    'files': file_info
                }), 200
                
            except Exception as e:
                self.logger.error(f"获取标定点文件列表时发生错误: {e}")
                return jsonify({
                    'success': False,
                    'message': f'服务器内部错误: {str(e)}'
                }), 500

        @self.app.route('/api/data/files', methods=['GET'])
        def list_data_files():
            """列出保存的数据文件"""
            try:
                with self.request_count_lock:
                    self.request_count += 1
                    
                file_type = request.args.get('type', 'all')  # all, calibration, analysis
                
                result = {'success': True, 'files': {}}
                
                if file_type in ['all', 'calibration']:
                    result['files']['calibration'] = self.data_storage.list_calibration_files()
                    
                if file_type in ['all', 'analysis']:
                    result['files']['analysis'] = self.data_storage.list_analysis_files()
                    
                result['data_directory'] = self.data_storage.get_data_directory()
                
                return jsonify(result), 200
                
            except Exception as e:
                self.logger.error(f"列出数据文件时发生错误: {e}")
                return jsonify({
                    'success': False,
                    'message': f'服务器内部错误: {str(e)}'
                }), 500
                
        @self.app.route('/api/analyze_image', methods=['POST'])
        def analyze_image():
            """图片温度分析接口"""
            try:
                with self.request_count_lock:
                    self.request_count += 1
                    
                # 验证是否有文件上传或base64数据
                image_file = None
                image_data = None
                regions = None
                save_result = True
                image_source = 'api_image_analysis'
                
                if 'image' in request.files:
                    # 处理文件上传
                    image_file = request.files['image']
                    if image_file.filename == '':
                        return jsonify({
                            'code': 400,
                            'success': False,
                            'message': '未选择图片文件',
                            'data': None
                        }), 400
                        
                    # 验证文件类型
                    if not self._is_allowed_file(image_file.filename):
                        return jsonify({
                            'code': 400,
                            'success': False,
                            'message': '不支持的图片格式，仅支持 jpg, jpeg, png, bmp',
                            'data': None
                        }), 400
                        
                    # 读取图片数据
                    image_data = image_file.read()
                    
                    # 从表单数据中获取regions参数
                    regions_str = request.form.get('regions')
                    if regions_str:
                        try:
                            regions = json.loads(regions_str)
                        except json.JSONDecodeError:
                            return jsonify({
                                'code': 400,
                                'success': False,
                                'message': 'regions参数格式错误，必须是有效的JSON格式',
                                'data': None
                            }), 400
                    
                    save_result = request.form.get('save_result', 'true').lower() == 'true'
                    image_source = request.form.get('image_source', 'api_image_analysis')
                    
                elif request.is_json:
                    # 处理JSON格式请求 - base64图片数据
                    data = request.get_json()
                    if not data:
                        return jsonify({
                            'code': 400,
                            'success': False,
                            'message': '请求体不能为空',
                            'data': None
                        }), 400
                        
                    base64_image = data.get('image')
                    if not base64_image:
                        return jsonify({
                            'code': 400,
                            'success': False,
                            'message': '缺少必需参数: image (base64格式)',
                            'data': None
                        }), 400
                        
                    try:
                        # 解码base64图片
                        if base64_image.startswith('data:image/'):
                            # 处理data URI格式
                            base64_image = base64_image.split(',')[1]
                        image_data = base64.b64decode(base64_image)
                    except Exception as e:
                        return jsonify({
                            'code': 400,
                            'success': False,
                            'message': f'base64图片解码失败: {str(e)}',
                            'data': None
                        }), 400
                        
                    # 从JSON中获取regions参数
                    regions = data.get('regions')
                    save_result = data.get('save_result', True)
                    image_source = data.get('image_source', 'api_image_analysis')
                    
                elif request.form:
                    # 处理form-data格式请求
                    regions_str = request.form.get('regions')
                    if regions_str:
                        try:
                            regions = json.loads(regions_str)
                        except json.JSONDecodeError:
                            return jsonify({
                                'code': 400,
                                'success': False,
                                'message': 'regions参数格式错误，必须是有效的JSON格式',
                                'data': None
                            }), 400
                    else:
                        regions = None
                        
                    save_result = request.form.get('save_result', 'true').lower() == 'true'
                    image_source = request.form.get('image_source', 'api_image_analysis')
                    
                else:
                    return jsonify({
                        'code': 400,
                        'success': False,
                        'message': '请求必须包含图片文件或base64图片数据',
                        'data': None
                    }), 400
                    
                # 验证regions参数
                if not regions:
                    return jsonify({
                        'code': 400,
                        'success': False,
                        'message': '缺少必需参数: regions',
                        'data': None
                    }), 400
                    
                if not isinstance(regions, list):
                    return jsonify({
                        'code': 400,
                        'success': False,
                        'message': 'regions参数必须是数组格式',
                        'data': None
                    }), 400
                    
                if len(regions) == 0:
                    return jsonify({
                        'code': 400,
                        'success': False,
                        'message': '至少需要提供一个分析区域',
                        'data': None
                    }), 400
                    
                # 验证区域数据格式
                for i, region in enumerate(regions):
                    if not isinstance(region, dict):
                        return jsonify({
                            'code': 400,
                            'success': False,
                            'message': f'区域{i+1}必须是对象格式',
                            'data': None
                        }), 400
                        
                    required_keys = ['x1', 'y1', 'x2', 'y2']
                    missing_keys = [key for key in required_keys if key not in region]
                    if missing_keys:
                        return jsonify({
                            'code': 400,
                            'success': False,
                            'message': f'区域{i+1}缺少必需的坐标参数: {missing_keys}',
                            'data': None
                        }), 400
                        
                    # 检查坐标类型和有效性
                    try:
                        x1, y1, x2, y2 = int(region['x1']), int(region['y1']), int(region['x2']), int(region['y2'])
                        if x1 >= x2 or y1 >= y2:
                            return jsonify({
                                'code': 400,
                                'success': False,
                                'message': f'区域{i+1}坐标无效: x1 < x2 且 y1 < y2',
                                'data': None
                            }), 400
                        if x1 < 0 or y1 < 0 or x2 < 0 or y2 < 0:
                            return jsonify({
                                'code': 400,
                                'success': False,
                                'message': f'区域{i+1}坐标不能为负数',
                                'data': None
                            }), 400
                    except (ValueError, TypeError):
                        return jsonify({
                            'code': 400,
                            'success': False,
                            'message': f'区域{i+1}的坐标参数必须为整数: {region}',
                            'data': None
                        }), 400
                        
                # 处理图片数据
                try:
                    # 将图片数据转换为OpenCV格式
                    nparr = np.frombuffer(image_data, np.uint8)
                    cv_image = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
                    
                    if cv_image is None:
                        return jsonify({
                            'code': 400,
                            'success': False,
                            'message': '图片数据无效或格式不支持',
                            'data': None
                        }), 400
                        
                    height, width = cv_image.shape[:2]
                    
                    # 验证区域坐标是否在图片范围内
                    for i, region in enumerate(regions):
                        x1, y1, x2, y2 = int(region['x1']), int(region['y1']), int(region['x2']), int(region['y2'])
                        if x2 > width or y2 > height:
                            return jsonify({
                                'code': 400,
                                'success': False,
                                'message': f'区域{i+1}坐标超出图片范围 (图片尺寸: {width}x{height})',
                                'data': None
                            }), 400
                            
                except Exception as e:
                    return jsonify({
                        'code': 500,
                        'success': False,
                        'message': f'图片处理失败: {str(e)}',
                        'data': None
                    }), 500
                    
                self.logger.info(f"收到图片温度分析请求，图片尺寸: {width}x{height}，共{len(regions)}个区域")
                
                # 执行温度分析
                result = self.thermal_service.analyze_image_regions(
                    image=cv_image,
                    regions=regions,
                    save_result=save_result,
                    image_source=image_source
                )
                
                if result['success']:
                    self.logger.info(f"图片温度分析完成，分析了{len(result.get('regions', []))}个区域")
                    
                    # 简化区域数据，只返回核心温度信息
                    simplified_regions = []
                    for region in result.get('regions', []):
                        temp_stats = region['temperature_stats']
                        simplified_regions.append({
                            'region_id': region['region_id'],
                            'coordinates': region['coordinates'],
                            'temperature': {
                                'min_temp': round(temp_stats['min_temp'], 2),
                                'max_temp': round(temp_stats['max_temp'], 2),
                                'avg_temp': round(temp_stats['avg_temp'], 2),
                                'min_position': temp_stats['min_position'],
                                'max_position': temp_stats['max_position']
                            }
                        })
                    
                    return jsonify({
                        'code': 200,
                        'success': True,
                        'message': '图片温度分析完成',
                        'data': simplified_regions
                    }), 200
                else:
                    self.logger.warning(f"图片温度分析失败: {result['message']}")
                    return jsonify({
                        'code': 500,
                        'success': False,
                        'message': result['message'],
                        'data': None
                    }), 500
                    
            except Exception as e:
                self.logger.error(f"图片温度分析时发生错误: {e}")
                self.logger.error(traceback.format_exc())
                return jsonify({
                    'code': 500,
                    'success': False,
                    'message': f'服务器内部错误: {str(e)}',
                    'data': None
                }), 500

        @self.app.route('/api/tsdk/process_rjpeg', methods=['POST'])
        def process_rjpeg():
            """处理R-JPEG文件接口（使用TSDK）"""
            try:
                with self.request_count_lock:
                    self.request_count += 1
                    
                # 验证是否有文件上传
                if 'rjpeg_file' not in request.files:
                    return jsonify({
                        'success': False,
                        'message': '缺少必需参数: rjpeg_file',
                        'data': None
                    }), 400
                    
                rjpeg_file = request.files['rjpeg_file']
                if rjpeg_file.filename == '':
                    return jsonify({
                        'success': False,
                        'message': '未选择R-JPEG文件',
                        'data': None
                    }), 400
                
                # 验证文件类型
                if not (rjpeg_file.filename.lower().endswith(('.r.jpg', '.rjpeg')) or 
                       self._is_allowed_file(rjpeg_file.filename)):
                    return jsonify({
                        'success': False,
                        'message': '不支持的文件格式，请上传R-JPEG格式文件',
                        'data': None
                    }), 400
                
                # 保存临时文件
                import tempfile
                tmp_path = None
                with tempfile.NamedTemporaryFile(delete=False, suffix='.rjpeg') as tmp_file:
                    rjpeg_file.save(tmp_file.name)
                    tmp_path = tmp_file.name
                
                try:
                    # 使用混合处理器处理R-JPEG文件
                    result = self.hybrid_processor.process_image(tmp_path, force_mode='tsdk')
                    
                    # 获取处理能力信息
                    capabilities = self.hybrid_processor.get_processing_capabilities()
                    
                    return jsonify({
                        'success': True,
                        'message': 'R-JPEG文件处理完成',
                        'data': {
                            'processing_method': result.get('processing_method', 'unknown'),
                            'accuracy_level': result.get('accuracy_level', 'unknown'),
                            'image_info': {
                                'width': result['width'],
                                'height': result['height'],
                                'file_path': result['file_path']
                            },
                            'temperature_stats': {
                                'min_temp': round(result['min_temp'], 2),
                                'max_temp': round(result['max_temp'], 2),
                                'mean_temp': round(result['mean_temp'], 2)
                            },
                            'capabilities': capabilities
                        }
                    }), 200
                    
                except Exception as e:
                    self.logger.error(f"R-JPEG处理失败: {e}")
                    return jsonify({
                        'success': False,
                        'message': f'R-JPEG处理失败: {str(e)}',
                        'data': None
                    }), 500
                    
                finally:
                    # 清理临时文件 - 暂时禁用避免os作用域错误
                    # try:
                    #     if tmp_path:
                    #         os.unlink(tmp_path)
                    # except Exception:
                    #     pass
                    pass
                        
            except Exception as e:
                self.logger.error(f"R-JPEG处理接口错误: {e}")
                return jsonify({
                    'success': False,
                    'message': f'服务器内部错误: {str(e)}',
                    'data': None
                }), 500

        @self.app.route('/api/tsdk/analyze_rjpeg_regions', methods=['POST'])
        def analyze_rjpeg_regions():
            """R-JPEG区域温度分析接口"""
            try:
                with self.request_count_lock:
                    self.request_count += 1
                    
                # 验证文件上传
                if 'rjpeg_file' not in request.files:
                    return jsonify({
                        'success': False,
                        'message': '缺少必需参数: rjpeg_file',
                        'data': None
                    }), 400
                    
                rjpeg_file = request.files['rjpeg_file']
                if rjpeg_file.filename == '':
                    return jsonify({
                        'success': False,
                        'message': '未选择R-JPEG文件',
                        'data': None
                    }), 400
                
                # 获取regions参数
                regions_str = request.form.get('regions')
                if not regions_str:
                    return jsonify({
                        'success': False,
                        'message': '缺少必需参数: regions',
                        'data': None
                    }), 400
                    
                try:
                    regions = json.loads(regions_str)
                except json.JSONDecodeError:
                    return jsonify({
                        'success': False,
                        'message': 'regions参数格式错误，必须是有效的JSON格式',
                        'data': None
                    }), 400
                
                # 验证regions格式
                if not isinstance(regions, list) or len(regions) == 0:
                    return jsonify({
                        'success': False,
                        'message': 'regions必须是非空数组',
                        'data': None
                    }), 400
                
                # 保存临时文件
                import tempfile
                tmp_path = None
                with tempfile.NamedTemporaryFile(delete=False, suffix='.rjpeg') as tmp_file:
                    rjpeg_file.save(tmp_file.name)
                    tmp_path = tmp_file.name
                
                try:
                    # 使用混合处理器处理R-JPEG文件
                    process_result = self.hybrid_processor.process_image(tmp_path, force_mode='tsdk')
                    
                    # 分析各个区域
                    region_results = []
                    for i, region in enumerate(regions):
                        try:
                            if not all(key in region for key in ['x1', 'y1', 'x2', 'y2']):
                                raise ValueError(f"区域{i+1}缺少必需的坐标参数")
                            
                            x1, y1, x2, y2 = int(region['x1']), int(region['y1']), int(region['x2']), int(region['y2'])
                            
                            # 获取区域温度统计
                            stats = self.hybrid_processor.get_region_temperature_stats(x1, y1, x2, y2)
                            
                            region_results.append({
                                'region_id': i + 1,
                                'coordinates': {'x1': x1, 'y1': y1, 'x2': x2, 'y2': y2},
                                'temperature_stats': {
                                    'min_temp': round(stats['min_temp'], 2),
                                    'max_temp': round(stats['max_temp'], 2),
                                    'mean_temp': round(stats['mean_temp'], 2),
                                    'std_temp': round(stats['std_temp'], 2),
                                    'median_temp': round(stats['median_temp'], 2),
                                    'min_position': stats['min_position'],
                                    'max_position': stats['max_position']
                                },
                                'processing_method': stats.get('method', 'tsdk')
                            })
                            
                        except Exception as e:
                            region_results.append({
                                'region_id': i + 1,
                                'error': f"区域分析失败: {str(e)}"
                            })
                    
                    return jsonify({
                        'success': True,
                        'message': f'R-JPEG区域温度分析完成，共分析{len(region_results)}个区域',
                        'data': {
                            'image_info': {
                                'width': process_result['width'],
                                'height': process_result['height'],
                                'processing_method': process_result.get('processing_method', 'tsdk'),
                                'accuracy_level': process_result.get('accuracy_level', 'high')
                            },
                            'regions': region_results
                        }
                    }), 200
                    
                except Exception as e:
                    self.logger.error(f"R-JPEG区域分析失败: {e}")
                    return jsonify({
                        'success': False,
                        'message': f'R-JPEG区域分析失败: {str(e)}',
                        'data': None
                    }), 500
                    
                finally:
                    # 清理临时文件 - 暂时禁用避免os作用域错误
                    # try:
                    #     if tmp_path:
                    #         os.unlink(tmp_path)
                    # except Exception:
                    #     pass
                    pass
                        
            except Exception as e:
                self.logger.error(f"R-JPEG区域分析接口错误: {e}")
                return jsonify({
                    'success': False,
                    'message': f'服务器内部错误: {str(e)}',
                    'data': None
                }), 500

        @self.app.route('/api/tsdk/get_point_temperature', methods=['POST'])
        def get_point_temperature():
            """获取R-JPEG文件中指定点的温度"""
            try:
                with self.request_count_lock:
                    self.request_count += 1
                
                # 验证文件上传
                if 'rjpeg_file' not in request.files:
                    return jsonify({
                        'success': False,
                        'message': '缺少必需参数: rjpeg_file'
                    }), 400
                
                rjpeg_file = request.files['rjpeg_file']
                x = request.form.get('x')
                y = request.form.get('y')
                
                if x is None or y is None:
                    return jsonify({
                        'success': False,
                        'message': '缺少必需参数: x, y坐标'
                    }), 400
                
                try:
                    x, y = int(x), int(y)
                except ValueError:
                    return jsonify({
                        'success': False,
                        'message': '坐标参数必须为整数'
                    }), 400
                
                # 保存临时文件
                import tempfile
                tmp_path = None
                with tempfile.NamedTemporaryFile(delete=False, suffix='.rjpeg') as tmp_file:
                    rjpeg_file.save(tmp_file.name)
                    tmp_path = tmp_file.name
                
                try:
                    # 使用TSDK处理R-JPEG文件
                    process_result = self.hybrid_processor.process_image(tmp_path, force_mode='tsdk')
                    
                    # 获取指定点的温度
                    temp_data = self.hybrid_processor.get_temperature_at_point(x, y)
                    
                    return jsonify({
                        'success': True,
                        'temperature': temp_data['temperature'],
                        'method': temp_data['method'],
                        'position': {'x': x, 'y': y},
                        'message': f'成功获取坐标({x}, {y})的温度'
                    }), 200
                    
                finally:
                    # 清理临时文件 - 暂时禁用避免os作用域错误
                    # if tmp_path and os.path.exists(tmp_path):
                    #     os.unlink(tmp_path)
                    pass
                        
            except Exception as e:
                self.logger.error(f"获取点温度失败: {e}")
                return jsonify({
                    'success': False,
                    'message': f'获取温度失败: {str(e)}'
                }), 500
        
        @self.app.route('/api/tsdk/capabilities', methods=['GET'])
        def get_tsdk_capabilities():
            """获取TSDK处理能力"""
            try:
                with self.request_count_lock:
                    self.request_count += 1
                    
                capabilities = self.hybrid_processor.get_processing_capabilities()
                
                return jsonify({
                    'success': True,
                    'message': 'TSDK能力检查完成',
                    'data': capabilities
                }), 200
                
            except Exception as e:
                self.logger.error(f"获取TSDK能力失败: {e}")
                return jsonify({
                    'success': False,
                    'message': f'获取能力失败: {str(e)}',
                    'data': None
                }), 500

        @self.app.route('/api/hybrid/process_image', methods=['POST'])
        def hybrid_process_image():
            """混合模式图像处理接口（自动选择最佳方法）"""
            try:
                with self.request_count_lock:
                    self.request_count += 1
                    
                # 验证文件上传
                if 'image_file' not in request.files:
                    return jsonify({
                        'success': False,
                        'message': '缺少必需参数: image_file',
                        'data': None
                    }), 400
                    
                image_file = request.files['image_file']
                if image_file.filename == '':
                    return jsonify({
                        'success': False,
                        'message': '未选择图像文件',
                        'data': None
                    }), 400
                
                # 获取处理模式参数
                force_mode = request.form.get('mode', 'auto')  # auto, tsdk, hsv, hybrid
                
                # 保存临时文件
                import tempfile
                file_ext = os.path.splitext(image_file.filename)[1]
                with tempfile.NamedTemporaryFile(delete=False, suffix=file_ext) as tmp_file:
                    image_file.save(tmp_file.name)
                    tmp_path = tmp_file.name
                
                try:
                    # 使用混合处理器处理图像
                    result = self.hybrid_processor.process_image(
                        tmp_path, 
                        force_mode=force_mode if force_mode != 'auto' else None
                    )
                    
                    return jsonify({
                        'success': True,
                        'message': '混合模式图像处理完成',
                        'data': {
                            'processing_method': result.get('processing_method', 'unknown'),
                            'accuracy_level': result.get('accuracy_level', 'unknown'),
                            'image_info': {
                                'width': result['width'],
                                'height': result['height'],
                                'file_path': result['file_path']
                            },
                            'temperature_stats': {
                                'min_temp': round(result['min_temp'], 2),
                                'max_temp': round(result['max_temp'], 2),
                                'mean_temp': round(result['mean_temp'], 2)
                            },
                            'method_comparison': result.get('method_comparison'),
                            'tsdk_data': result.get('tsdk_data'),
                            'hsv_data': result.get('hsv_data')
                        }
                    }), 200
                    
                except Exception as e:
                    self.logger.error(f"混合模式处理失败: {e}")
                    return jsonify({
                        'success': False,
                        'message': f'混合模式处理失败: {str(e)}',
                        'data': None
                    }), 500
                    
                finally:
                    # 清理临时文件 - 暂时禁用避免os作用域错误
                    # try:
                    #     if tmp_path:
                    #         os.unlink(tmp_path)
                    # except Exception:
                    #     pass
                    pass
                        
            except Exception as e:
                self.logger.error(f"混合模式处理接口错误: {e}")
                return jsonify({
                    'success': False,
                    'message': f'服务器内部错误: {str(e)}',
                    'data': None
                }), 500
                
        # Web界面静态文件服务
        @self.app.route('/')
        def index():
            """主页面 - 重定向到Web界面"""
            return redirect('/web')
            
        @self.app.route('/web')
        def web_interface():
            """Web界面主页"""
            try:
                # 获取项目根目录
                current_dir = os.path.dirname(os.path.abspath(__file__))
                project_root = os.path.dirname(os.path.dirname(current_dir))
                web_dir = os.path.join(project_root, 'web')
                
                if not os.path.exists(os.path.join(web_dir, 'index.html')):
                    raise FileNotFoundError(f"Web界面文件不存在: {web_dir}")
                    
                return send_from_directory(web_dir, 'index.html')
            except Exception as e:
                self.logger.error(f"Web界面访问失败: {e}")
                return jsonify({
                    'success': False,
                    'message': f'Web界面无法访问: {str(e)}'
                }), 500
                
        @self.app.route('/static/<path:filename>')
        def serve_static(filename):
            """静态文件服务（CSS、JS、图片等）"""
            try:
                # 获取项目根目录
                current_dir = os.path.dirname(os.path.abspath(__file__))
                project_root = os.path.dirname(os.path.dirname(current_dir))
                static_dir = os.path.join(project_root, 'web', 'static')
                
                self.logger.info(f"尝试访问静态文件: {filename}, 静态目录: {static_dir}")
                
                if not os.path.exists(static_dir):
                    raise FileNotFoundError(f"静态文件目录不存在: {static_dir}")
                    
                return send_from_directory(static_dir, filename)
            except Exception as e:
                self.logger.error(f"静态文件服务失败: {e}")
                return jsonify({
                    'success': False,
                    'message': f'静态文件无法访问: {str(e)}'
                }), 404

        @self.app.errorhandler(404)
        def not_found(error):
            """404错误处理"""
            # 检查是否是API请求
            if request.path.startswith('/api/'):
                return jsonify({
                    'success': False,
                    'message': 'API端点不存在',
                    'available_endpoints': [
                        'GET /api/health - 健康检查',
                        'POST /api/start_stream - 开启温度分析',
                        'POST /api/stop_stream - 关闭温度分析',
                        'POST /api/analyze_regions - 区域温度分析',
                        'POST /api/analyze_image - 图片温度分析',
                        'GET /api/stream_status - 获取流状态',
                        'POST /api/calibration - 管理标定点',
                        'GET /api/data/files - 列出数据文件',
                        'POST /api/tsdk/process_rjpeg - 处理R-JPEG文件（TSDK）',
                        'POST /api/tsdk/analyze_rjpeg_regions - R-JPEG区域温度分析',
                        'GET /api/tsdk/capabilities - 获取TSDK处理能力',
                        'POST /api/hybrid/process_image - 混合模式图像处理'
                    ]
                }), 404
            else:
                # 非API请求，重定向到Web界面
                return redirect('/web')
            
        @self.app.errorhandler(500)
        def internal_error(error):
            """500错误处理"""
            return jsonify({
                'success': False,
                'message': '服务器内部错误，请查看服务器日志'
            }), 500
            
    def run(self):
        """启动API服务器"""
        self.server_start_time = time.time()
        self.logger.info(f"启动热成像温度分析API服务器")
        self.logger.info(f"服务地址: http://{self.host}:{self.port}")
        self.logger.info(f"健康检查: http://{self.host}:{self.port}/api/health")
        
        try:
            self.app.run(
                host=self.host,
                port=self.port,
                debug=self.debug,
                threaded=True,
                use_reloader=False  # 避免重复初始化
            )
        except KeyboardInterrupt:
            self.logger.info("收到停止信号，正在关闭服务器...")
            self.cleanup()
        except Exception as e:
            self.logger.error(f"服务器启动失败: {e}")
            raise
    
    def _generate_grid_points(self, width: int, height: int, grid_width: int, grid_height: int, full_coverage: bool = False) -> list:
        """
        生成网格标定点坐标
        
        Args:
            width: 图像宽度
            height: 图像高度
            grid_width: 网格列数
            grid_height: 网格行数
            full_coverage: 是否全图覆盖（无边界留白）
            
        Returns:
            List[Dict]: 网格点坐标列表
        """
        grid_points = []
        
        if full_coverage:
            # 全图覆盖模式：网格点分布到图像边缘
            step_x = (width - 1) / (grid_width - 1) if grid_width > 1 else 0
            step_y = (height - 1) / (grid_height - 1) if grid_height > 1 else 0
            
            for row in range(grid_height):
                for col in range(grid_width):
                    x = int(col * step_x)
                    y = int(row * step_y)
                    
                    # 确保坐标在有效范围内
                    x = max(0, min(width - 1, x))
                    y = max(0, min(height - 1, y))
                    
                    grid_points.append({'x': x, 'y': y})
        else:
            # 传统模式：保留10%边界空间
            margin_x = width * 0.1
            margin_y = height * 0.1
            
            usable_width = width - 2 * margin_x
            usable_height = height - 2 * margin_y
            
            step_x = usable_width / (grid_width - 1) if grid_width > 1 else 0
            step_y = usable_height / (grid_height - 1) if grid_height > 1 else 0
            
            for row in range(grid_height):
                for col in range(grid_width):
                    x = int(margin_x + col * step_x)
                    y = int(margin_y + row * step_y)
                    
                    # 确保坐标在有效范围内
                    x = max(0, min(width - 1, x))
                    y = max(0, min(height - 1, y))
                    
                    grid_points.append({'x': x, 'y': y})
        
        coverage_mode = "全图覆盖" if full_coverage else "预留边界"
        self.logger.info(f"生成{grid_width}x{grid_height}网格，共{len(grid_points)}个标定点，模式: {coverage_mode}")
        return grid_points
            
    def cleanup(self):
        """清理资源"""
        self.logger.info("正在清理服务器资源...")
        self.thermal_service.cleanup()
        if hasattr(self, 'hybrid_processor') and self.hybrid_processor:
            self.hybrid_processor.cleanup()
        self.logger.info("服务器已关闭")


def create_app(config: Dict[str, Any] = None) -> ThermalAPIServer:
    """
    创建API服务器实例
    
    Args:
        config: 配置字典
        
    Returns:
        API服务器实例
    """
    if config is None:
        config = {}
        
    return ThermalAPIServer(
        host=config.get('host', '0.0.0.0'),
        port=config.get('port', 5000),
        debug=config.get('debug', False)
    )


if __name__ == '__main__':
    # 命令行启动
    import argparse
    
    parser = argparse.ArgumentParser(description='红外温度分析API服务器')
    parser.add_argument('--host', default='0.0.0.0', help='服务器主机地址')
    parser.add_argument('--port', type=int, default=5000, help='服务器端口')
    parser.add_argument('--debug', action='store_true', help='启用调试模式')
    
    args = parser.parse_args()
    
    # 创建并启动服务器
    server = create_app({
        'host': args.host,
        'port': args.port,
        'debug': args.debug
    })
    
    try:
        server.run()
    except KeyboardInterrupt:
        print("\n服务器已停止")
    except Exception as e:
        print(f"服务器启动失败: {e}")